package com.yeskery.nut.plugin;

import com.yeskery.nut.application.ApplicationType;
import com.yeskery.nut.application.NutApplication;

import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;

/**
 * 基础插件初始化器
 * @author Yeskery
 * 2023/7/24
 */
public abstract class BasePluginInitializer {

    /** 日志对象 */
    private static final Logger logger = Logger.getLogger(BasePluginInitializer.class.getName());

    /** 已处理的插件集合 */
    private final List<Plugin> executePlugins = new ArrayList<>();


    /**
     * 初始化插件
     * @param nutApplication Nut应用对象
     * @param bindContext 插件绑定上下文对象
     */
    public void initialize(NutApplication nutApplication, BindContext bindContext) {
        initialize(nutApplication, bindContext, getPlugins());
    }

    /**
     * 初始化插件
     * @param nutApplication Nut应用对象
     * @param bindContext 插件绑定上下文对象
     * @param plugins 需要执行的插件的集合
     */
    public void initialize(NutApplication nutApplication, BindContext bindContext, Collection<Plugin> plugins) {
        if (plugins == null || plugins.isEmpty()) {
            return;
        }
        List<Plugin> pluginList = plugins.stream().sorted(Comparator.comparing(Plugin::getOrder)).collect(Collectors.toList());
        // 先执行基础插件
        for (Plugin plugin : pluginList) {
            if (plugin instanceof PriorityPlugin && !executePlugins.contains(plugin)) {
                beforeExecutePluginBindMethod(nutApplication, bindContext, plugin);
                doExecutePluginBindMethod(nutApplication, bindContext, plugin);
                afterExecutePluginBindMethod(nutApplication, bindContext, plugin);
                executePlugins.add(plugin);
            }
        }
        for (Plugin plugin : pluginList) {
            if (!executePlugins.contains(plugin)) {
                beforeExecutePluginBindMethod(nutApplication, bindContext, plugin);
                doExecutePluginBindMethod(nutApplication, bindContext, plugin);
                afterExecutePluginBindMethod(nutApplication, bindContext, plugin);
                executePlugins.add(plugin);
            }
        }
    }

    /**
     * 获取当前的插件集合
     * @return 当前的插件集合
     */
    protected abstract Collection<Plugin> getPlugins();

    /**
     * 执行插件bind方法之前的扩展方法
     * @param nutApplication Nut应用对象
     * @param bindContext 插件绑定上下文对象
     * @param plugin 插件对象
     */
    protected void beforeExecutePluginBindMethod(NutApplication nutApplication, BindContext bindContext, Plugin plugin) {
    }

    /**
     * 执行插件bind方法之后的扩展方法
     * @param nutApplication Nut应用对象
     * @param bindContext 插件绑定上下文对象
     * @param plugin 插件对象
     */
    protected void afterExecutePluginBindMethod(NutApplication nutApplication, BindContext bindContext, Plugin plugin) {
    }

    /**
     * 执行插件绑定方法
     * @param nutApplication Nut应用对象
     * @param plugin 插件对象
     */
    private void doExecutePluginBindMethod(NutApplication nutApplication, BindContext bindContext, Plugin plugin) {
        try {
            plugin.bind(bindContext);
            ApplicationType applicationType = nutApplication.getApplicationType();
            boolean isWebApplicationType = ApplicationType.isWebApplicationType(applicationType);
            if (!isWebApplicationType && nutApplication.getNutWebConfigure().getPluginManager().isWebPlugin(plugin)) {
                logger.warning("Web Plugin [" + plugin.getClass().getName() + "] Run With ["
                        + nutApplication.getApplicationType() + "], Web Plugin's Enhance Method Can Not Execute.");
            }
        } catch (Exception e) {
            String className = plugin.getClass().getName();
            logger.logp(Level.SEVERE, className, "bind",
                    "Plugin [" + className + "] Bind Method Execute Failure.", e);
        }
    }
}
